/*
 * header.c
 *
 *  Created on: 2014年12月24日
 *      Author: chens
 *      用来生成人脸检测算法使用的头文件，可以生成 静态 分类器对象
 *      或者生成构造分类器对象的函数
 */

#include <cstring>
#include <cstdio>
#include <iostream>
#include <fstream>

using namespace std;

struct SimpleClassifier {
	double thresh;
	double error;
	int parity;
	int type; // which type of feature?
	int x1, x2, x3, x4, y1, y2, y3, y4;
};
struct AdaBoostClassifier {
	int count;
	SimpleClassifier* scs;
	double* alphas;
	double thresh;
};

struct CascadeClassifier {
	int count;
	AdaBoostClassifier* ac;
};

/**************************************************/

/*
 * @brief	从文件读取分类器
 * @param	cascade_filename: 保存分类数据的文件名
 * @param	cascade:出参，用来填充数据
 * @return	读取完成返回true， 失败返回false
 */
static bool read_cascade_file(const char* cascade_filename,
		CascadeClassifier *cascade)
{
	if (cascade_filename == NULL || cascade == NULL) {
		return false;
	}

	ifstream f;

	f.open(cascade_filename);
	if (!f.is_open())
		return false;

	f >> cascade->count;
	f.ignore(256, '\n');
	if (cascade->count < 1) {
		f.close();
		return false;
	}
	cascade->ac = new AdaBoostClassifier[cascade->count];
	int i;
	for (i = 0; i < cascade->count; i++) {
		f >> cascade->ac[i].count;
		f.ignore(256, '\n');
//		printf("----->%d\n", cascade->ac[i].count);

		cascade->ac[i].scs = new SimpleClassifier[cascade->ac[i].count];
		cascade->ac[i].alphas = new double[cascade->ac[i].count];

		f >> cascade->ac[i].thresh;
		f.ignore(256, '\n');

		for (int j = 0; j < cascade->ac[i].count; j++) {
			f >> cascade->ac[i].alphas[j];
		}
		f.ignore(256, '\n');

		for (int k = 0; k < cascade->ac[i].count; k++) {
			f >> cascade->ac[i].scs[k].thresh
					>> cascade->ac[i].scs[k].parity
					>> cascade->ac[i].scs[k].type;
			f >> cascade->ac[i].scs[k].x1
					>> cascade->ac[i].scs[k].x2
					>> cascade->ac[i].scs[k].x3
					>> cascade->ac[i].scs[k].x4
					>> cascade->ac[i].scs[k].y1
					>> cascade->ac[i].scs[k].y2
					>> cascade->ac[i].scs[k].y3
					>> cascade->ac[i].scs[k].y4;
			f.ignore(256, '\n');
		}
		f.ignore(256, '\n');
	}
	f.close();
	return true;
}

/*************************************************************/

/*
 * @brief	将分类器的定义写如要生成的头文件
 */
static inline void write_def(ofstream &of)
{
	of << "struct SimpleClassifier {\n";
	of << "\tdouble thresh;\n";
	of << "\tdouble error;\n";
	of << "\tint parity;\n";
	of << "\tint type;\n";
	of << "\tint x1, x2, x3, x4, y1, y2, y3, y4;\n";
	of << "};\n\n";

	of << "struct AdaBoostClassifier {\n";
	of << "\tint count;\n";
	of << "\tstruct SimpleClassifier* scs;\n";
	of << "\tdouble* alphas;\n";
	of << "\tdouble thresh;\n";
	of << "};\n";
	of << "\n";
	of << "struct CascadeClassifier {\n";
	of << "\tint count;\n";
	of << "\tstruct AdaBoostClassifier* ac;\n";
	of << "};\n\n";
}

/*
 * @brief	将分类器中所有 SimpleClassifier 实例写入头文件中
 */
static inline void write_sc(ofstream &of, const CascadeClassifier *cascade)
{
	int i, j, k;
	for (i = 0; i < cascade->count; i++) {

		const struct AdaBoostClassifier *ac = &(cascade->ac[i]);

		of << "static struct SimpleClassifier g_ac_sc" << i
				<< "[] = {\n";
		for (j = 0; j < ac->count; j++) {
			//定义一个 SimpleClassifier 数组
			of << "\t{";
			const struct SimpleClassifier *ptr = &(ac->scs[j]);
			of << ptr->thresh << "," << ptr->error << ","
					<< ptr->parity << "," << ptr->type
					<< ",";
			of << ptr->x1 << "," << ptr->x2 << "," << ptr->x3 << ","
					<< ptr->x4 << "," << ptr->y1 << ","
					<< ptr->y2 << "," << ptr->y3 << ","
					<< ptr->y4;
			of << "}";
			if (j != ac->count - 1)
				of << ",";
			of << "\n";
		}
		of << "};\n\n";

		of << "static double g_ac_double" << i << "[] = {";

		for (k = 0; k < ac->count; k++) {
			of << ac->alphas[k];
			if (k != ac->count - 1)
				of << ",";
		}
//		if (j != ac->count - 1)
//			of << ",";
//		of << "\n";

		of << "};\n\n";
	}
}

static inline void write_ac(ofstream &of, const CascadeClassifier *cascade)
{
	int i;
	of << "static struct AdaBoostClassifier g_ac[] = {\n";
	for (i = 0; i < cascade->count; i++) {
		of << "\t{";

		of << cascade->ac[i].count << ",";

		of << "g_ac_sc" << i << ",";
		of << "g_ac_double" << i << ",";
		of << cascade->ac[i].thresh << "}";
		if (i != cascade->count - 1)
			of << ",";
		of << "\n";
	}
	of << "};\n\n";
}

static inline void write_cc(ofstream &of, const CascadeClassifier *cascade)
{
	of << "static struct CascadeClassifier g_cascade = {";

	of << cascade->count << "," << "g_ac";

	of << "};\n\n";
}

static inline bool write_objects(ofstream &of, const CascadeClassifier *cascade)
{
	if (cascade == NULL)
		return false;

	write_sc(of, cascade);
	write_ac(of, cascade);
	write_cc(of, cascade);

	return true;
}

/******************************************************************/
// 注释这两个函数是先写出 malloc 方式构造分类器的函数， 再将它们用代码生成
//static int cascade_size(const CascadeClassifier *cascade)
//{
//	int i;
//	int size = 0;
//	size += sizeof(CascadeClassifier);
//	size += cascade->count + sizeof(AdaBoostClassifier);
//	for (i = 0; i < cascade->count; i++) {
//		size += (cascade->ac[i].count) * sizeof(SimpleClassifier);
//	}
//	return size;
//}
//
//static void * create_cascade(CascadeClassifier *cascade,
//		CascadeClassifier **obj)
//{
//	int i;
//	void *ptr = NULL;
//	if (cascade == NULL || obj == NULL)
//		return NULL;
//
//	ptr = malloc(cascade_size(cascade));
//
//	if (ptr == NULL)
//		return NULL;
//
//	(*obj) = (CascadeClassifier *) ptr;
//	(*obj)->count = cascade->count;
//	(*obj)->ac = (AdaBoostClassifier *) (ptr + 1);
//
//	for (i = 0; i < (*obj)->count; i++) {
//
//	}
//
//}
static bool write_constructor(ofstream &of, const CascadeClassifier *cascade)
{
	return true;
}

static inline void write_header_begin(ofstream &of, const char *fname)
{
	char temp[256];
	memset(temp, 0, 256);
	for (int i = 0; i < 255 && fname[i] != 0; i++)
		temp[i] = isalnum(fname[i]) ? toupper(fname[i]) : '_';

	of << "/***** this file is generated automatically *****/\n\n\n";
	of << "#ifndef " << temp << "\n";
	of << "#define " << temp << "\n\n\n";
}

static inline void write_header_end(ofstream &of)
{
	of << "#endif\n";
}

/***********************************************/

enum HEADER_TYPE {
	STATIC_OBJ,  // 只生成全局静态对象
	CONSTRUCTOR, //
	BOTH
};

/*
 * @brief	根据需求生成头文件
 * @param	fname: 要生成的头文件名称
 * @param	type: 生成规则
 * @param	cascade: 分类器实例
 * return	成功返回true， 失败返回false
 */
static bool generate_file(const char *fname, enum HEADER_TYPE type,
		const CascadeClassifier *cascade)
{
	if (fname == NULL || cascade == NULL)
		return false;

	ofstream of;
	of.open(fname);
	if (!of.is_open())
		return false;

	write_header_begin(of, fname);
	write_def(of);
	if (type == STATIC_OBJ || type == BOTH)
		write_objects(of, cascade);

	if (type == CONSTRUCTOR || type == BOTH)
		write_constructor(of, cascade);

	write_header_end(of);
	of.close();
	return true;
}

int main(int argc, char **argv)
{
	if (argc < 3) {
		printf("Usage: %s <datafile>(in) <header>(out)\n", argv[0]);
		return 0;
	}

	CascadeClassifier cfg;
	if (read_cascade_file(argv[1], &cfg))
		if (generate_file(argv[2], STATIC_OBJ, &cfg))
			cout << "Header file (" << argv[2]
					<< ") generated successfully." << endl;
		else
			cout << "Read file (" << argv[1] << ") error." << endl;
}

